package hivMultiCompartment;


import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import uchicago.src.sim.analysis.OpenSequenceGraph;
import uchicago.src.sim.analysis.Sequence;
import uchicago.src.sim.engine.AbstractGUIController;
import uchicago.src.sim.engine.Controller;
import uchicago.src.sim.gui.ColorMap;
import uchicago.src.sim.gui.DisplaySurface;
import uchicago.src.sim.gui.Object2DDisplay;
import uchicago.src.sim.gui.Value2DDisplay;


public class GUIModel extends Model {
	
	//Lymph node 
    private Object2DDisplay  lnDisplayCells;	// 2D Object lattice -> display (Repast)
    private Object2DDisplay  lnDisplayPorts;	// 2D Object lattice -> display (Repast)
    private Value2DDisplay   lnDisplayVirusAb;
    
    //Thymus
    private Object2DDisplay  thymusDisplayCells;	// 2D Object lattice -> display (Repast)
    private Object2DDisplay  thymusDisplayPorts;	// 2D Object lattice -> display (Repast)
    private Value2DDisplay   thymusDisplayVirusAb;
    
    private DisplaySurface	 dsurfL;		    // display surface (RePast)
    private DisplaySurface	 dsurfT;		    // display surface (RePast)
    public  OpenSequenceGraph		graphBloodStream; //plot of blood stream cells

	// colormap and scaling variables
	
	public static ColorMap		 virusAbColorMap;
	public static final int colorMapMax = colorMapSize * colorMapSize;
	public static final double colorMapTick = 1.0 / colorMapSize;

	
	/////////////////////////////////////////////////////////////////////
	// setup
	//
	// this runs automatically when the model starts
	// and when you click the reload button, to "tear down" any 
	// existing display objects, and get ready to initialize 
	// them at the start of the next 'run'.
	//
	public void setup() {
	   	//System.out.printf( "==> GUIModel setup() called...\n" );

		super.setup();  // the super class does conceptual-model setup

		// NOTE: you may want to set these next two to 'true'
		// if you are on a windows machine.  that would tell repast
		// to by default send System.out and .err output to
		// a special repast output window.
		AbstractGUIController.CONSOLE_ERR = false;
		AbstractGUIController.CONSOLE_OUT = false;
		AbstractGUIController.UPDATE_PROBES = true;

		if ( dsurfL != null ) dsurfL.dispose();
		if ( dsurfT != null ) dsurfT.dispose();
		if ( graphBloodStream != null ) graphBloodStream.dispose();
		
		dsurfL = null;
		dsurfT = null;
		graphBloodStream = null;

	
		// init, setup and turn on the modelMinipulator stuff (in custom actions)
		modelManipulator.init();
		// one custom action to just print the bug list
		modelManipulator.addButton( "Print Cells", 
			new ActionListener() {
				public void actionPerformed(ActionEvent evt) {
					System.out.printf( "printCells...\n" );
				}
			} 
	    );
		
		if ( rDebug > 0 )
			System.out.printf( "<== GUIModel setup() done.\n" );
	}

	/////////////////////////////////////////////////////////////////////
	// begin
	//
	// this runs when you click the "initialize" button
	// (the button with the single arrow that goes around in a circle)
	//
	public void begin()	{
		DMSG(1, "==> enter GUIModel-begin()" );
		buildModel();     			// the base model does this
		buildDisplay();
		buildSchedule();
		DMSG(1, "<== leave GUIModel-begin() done." );
	}

	/////////////////////////////////////////////////////////////////////
	// buildDisplay
	//
	// builds the display and display related things
	//
	public void buildDisplay() {
		if ( rDebug > 0 )
			System.out.printf( "==> GUIModel buildDisplay...\n" );

		// create the object we see as the 2D "LN" on the screen 
		dsurfL = new DisplaySurface( this, "LN Display" );
		registerDisplaySurface( "Main Display", dsurfL );
		
		// create the object we see as the 2D "Thymus" on the screen 
		dsurfT = new DisplaySurface( this, "Thymus Display" );
		registerDisplaySurface( "Second Display", dsurfT );

		//
		virusAbColorMap = new ColorMap ();
		for (int i = 0; i < colorMapMax; ++i) {
			virusAbColorMap.mapColor ( i, (i/colorMapSize)*colorMapTick, (i%colorMapSize)*colorMapTick, (i%colorMapSize)*colorMapTick );
			//virusAbColorMap.mapColor ( i, (double)(colorMapMax - 1 - i)/colorMapMax, (double)i/colorMapMax, (double)i/colorMapMax);
			//virusAbColorMap.mapColor(i, 1.0, 0, 0);
		}

		// enable the custom action(s)
		modelManipulator.setEnabled( true );
	
		// create mapper object, from 2D GridWorld to the display surface
		lnDisplayCells = new Object2DDisplay( lymphNode.cellSpace );
		// speed up display of ants -- just display them!
        lnDisplayCells.setObjectList( lymphNode.cellList );
        
        lnDisplayPorts = new Object2DDisplay( lymphNode.cellSpace );
        lnDisplayPorts.setObjectList(lymphNode.allPorts );
        
        lnDisplayVirusAb = new Value2DDisplay(lymphNode.virusAntibodyMap, virusAbColorMap);
        //lnDisplayVirusAb = new Value2DDisplay(lymphNode.antibodySpace, virusAbColorMap);
        lnDisplayVirusAb.setDisplayMapping(1, 0);
        
        thymusDisplayVirusAb = new Value2DDisplay(thymus.virusAntibodyMap, virusAbColorMap);
        thymusDisplayVirusAb.setDisplayMapping(1, 0);
        
     // create mapper object, from 2D GridWorld to the display surface
        thymusDisplayCells = new Object2DDisplay( thymus.cellSpace );
     	// speed up display of ants -- just display them!
        thymusDisplayCells.setObjectList( thymus.cellList );

        thymusDisplayPorts = new Object2DDisplay( thymus.cellSpace );
        thymusDisplayPorts.setObjectList( thymus.allPorts );
        
        dsurfL.addDisplayable(lnDisplayVirusAb, "virus-antibody");
        dsurfL.addDisplayableProbeable( lnDisplayCells, "LN, cells");
        dsurfL.addDisplayableProbeable( lnDisplayPorts, "LN, Ports");
        addSimEventListener( dsurfL );  // link to the other parts of the repast gui
        
        dsurfT.addDisplayable(thymusDisplayVirusAb, "virus-antibody");
        dsurfT.addDisplayableProbeable( thymusDisplayCells, "Thymus, cells");
        dsurfT.addDisplayableProbeable( thymusDisplayPorts, "Thymus, ports");
        addSimEventListener( dsurfT );  // link to the other parts of the repast gui

		dsurfL.display();
		dsurfT.display();
		
		
//		class SeqLymphCellSize implements Sequence {
//			public double getSValue() {
//				return getCellTypeNr(bloodStream, Cell.class);
//			}
//		}
//		class SeqLymphCellSize implements Sequence {
//			public double getSValue() {
//				return getCellTypeNr(lymphNode, Cell.class);
//			}
//		}
//		class SeqLymphVirusSize implements Sequence {
//			public double getSValue() {
//				return getVirusNr(lymphNode)/30;
//			}
//		}
//		class SeqThymusCellSize implements Sequence {
//			public double getSValue() {
//				return getCellTypeNr(thymus, Cell.class);
//			}
//		}
		class SeqThymusVirusSize implements Sequence {
			public double getSValue() {
				return getVirusNr(thymus)/10;
			}
		}
		class SeqBloodCD4TCellSize implements Sequence {
			public double getSValue() {
				return getCellTypeNr(bloodStream, CD4TCell.class);
			}
		}
		class SeqBloodVirusSize implements Sequence {
			public double getSValue() {
				return getVirusNr(bloodStream)/10;
			}
		}
		
		graphBloodStream = new OpenSequenceGraph("BloodStream Cell Population", this);
		graphBloodStream.setXRange(0, 20000);
		graphBloodStream.setYRange(-1, 1000);
		graphBloodStream.setYIncrement( 1000 );
		graphBloodStream.setXIncrement( 10000 );
		graphBloodStream.setAxisTitles("time", "Cell Number");
		graphBloodStream.addSequence("Blood CD4+ Cell count", new SeqBloodCD4TCellSize(), Color.GREEN);
		graphBloodStream.addSequence("Blood virus count / 10", new SeqBloodVirusSize(), Color.RED);
		//graphBloodStream.addSequence("LN Cell count", new SeqLymphCellSize(), Color.BLUE);
		//graphBloodStream.addSequence("LN virus count / 30", new SeqLymphVirusSize(), Color.PINK);
		//graphBloodStream.addSequence("Thymus+ Cell count", new SeqThymusCellSize(), Color.CYAN);
		graphBloodStream.addSequence("Thymus virus count /10 ", new SeqThymusVirusSize(), Color.ORANGE);
		
		graphBloodStream.display();

		
		if ( rDebug > 0 )
			System.out.printf( "<== GUIModel buildDisplay done.\n" );
	}
	


	////////////////////////////////////////////////////////////////
	// buildSchedule
	//
	// This builds the entire schedule, i.e., 
	//  - the base model step (calls stepReport)
	//  - display steps.

	public void buildSchedule() {

		if ( rDebug > 0 )
			System.out.printf( "==> GUIModel buildSchedule...\n" );

		// schedule the current GUIModel's step() function
		// to execute every time step starting with time step 0
		schedule.scheduleActionBeginning( 0, this, "step" );

		// schedule the current GUIModel's processEndOfRun() 
		// function to execute at the end of the run
		schedule.scheduleActionAtEnd( this, "processEndOfRun" );
	}


	///////////////////////////////////////////////////////////////////////////////
	// step
	//
	// executed each step of the model.
	// Ask the super-class to do its step() method,
	// and then this does display related activities.
	//
	public void step() {

		super.step();			// the model does whatever it does

		// add things after this for all displays (graphs, etc)
		dsurfL.updateDisplay();
		dsurfT.updateDisplay();
		
		graphBloodStream.step();
	}

	// processEndOfRun
	// called once, at end of run.
	public void processEndOfRun ( ) {
		if ( rDebug > 0 )  
			System.out.printf("\n\n===== GUIModel processEndOfRun =====\n\n" );
		applyAnyStoredChanges();
		endReportFile();
		this.fireStopSim();
	}


/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//   ****  NO NEEd TO CHANGE THE REST OF THIS  *****

	////////////////////////////////////////////////////////////////////
	// main entry point
	public static void main( String[] args ) {

		uchicago.src.sim.engine.SimInit init =
			new uchicago.src.sim.engine.SimInit();
		GUIModel model = new GUIModel();

		//System.out.printf("==> GUIMOdel main...\n" );

		// set the type of model class, this is necessary
		// so the parameters object knows whether or not
		// to do GUI related updates of panels,etc when a
		// parameter is changed
		model.setModelType("GUIModel");

        // Do this to set the Update Probes option to true in the
        // Repast Actions panel
        Controller.UPDATE_PROBES = true;

		model.setCommandLineArgs( args );
		init.loadModel( model, null, false ); // does setup()

		// this new function calls ProbeUtilities.updateProbePanels() and 
		// ProbeUtilities.updateModelProbePanel()
		model.updateAllProbePanels();

	}

}
